﻿using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Text;
using System.Xml;
using todo.Model;

namespace todo.Persistence
{
    public class TodoListWriter
    {
        public static void Save(TodoList todoList, string fileName)
        {
            var doc = new XmlDocument();
            var declaration = doc.CreateXmlDeclaration("1.0", "utf-8", null);
            doc.AppendChild(declaration);

            var docElem = doc.CreateElement("todolist");
            if (!string.IsNullOrEmpty(todoList.Id))
            {
                docElem.SetAttribute("id", todoList.Id);
            }

            AddChildElement(doc, docElem, "title", todoList.Title);
            AddChildElement(doc, docElem, "author", todoList.Author);
            AddChildElement(doc, docElem, "comments", todoList.Comments);
            AddChildElement(doc, docElem, "updateTime", 
                todoList.UpdateTime.ToString("yyyy-MM-dd HH:mm:ss"));

            //
//            var colWidths = AppFuncs.GetColWidthsString(todoList.ColWidths);
//            AddChildElement(doc, docElem, "colWidths", colWidths);

            //
            docElem.AppendChild(CreateTodosElement(doc, todoList.Todos));

            doc.AppendChild(docElem);

            using (var sw = new StreamWriter(fileName, false, Encoding.UTF8))
            {
                doc.Save(sw);
            }
        }

        private static XmlElement CreateTodosElement(XmlDocument doc, IList<Todo> todos)
        {
            var todosElem = doc.CreateElement("todos");
            foreach (var todo in todos)
            {
                var todoElem = CreateTodoElement(doc, todo);
                todosElem.AppendChild(todoElem);
            }
            return todosElem;
        }

        private static XmlElement CreateTodoElement(XmlDocument doc, Todo todo)
        {
            var elem = doc.CreateElement("todo");
            var title = todo.Title;
            if (!string.IsNullOrEmpty(title))
            {
                title = title.Replace("\n", "\r\n");
            }
            AddChildElement(doc, elem, "title", title);
            AddChildElement(doc, elem, "progress",
                    todo.Progress.ToString(CultureInfo.InvariantCulture));
            AddChildElement(doc, elem, "due", todo.Due);
            AddChildElement(doc, elem, "description", todo.Description);
            AddChildElement(doc, elem, "checked",
                    todo.Checked.ToString(CultureInfo.InvariantCulture));
            AddChildElement(doc, elem, "active", todo.Active.ToString(CultureInfo.InvariantCulture));
            if (todo.Todos != null && todo.Todos.Count > 0)
            {
                var todosElem = CreateTodosElement(doc, todo.Todos);
                elem.AppendChild(todosElem);
            }
            if (!string.IsNullOrEmpty(todo.Id))
            {
                elem.SetAttribute("id", todo.Id);
            }
            if (todo.DisplayStyle != DisplayStyle.Normal)
            {
                elem.SetAttribute("displayStyle", todo.DisplayStyle.ToString());
            }
            if (!string.IsNullOrEmpty(todo.Color) && todo.Color != "none")
            {
                elem.SetAttribute("color", todo.Color);
            }
            if (todo.CreateTime != DateTime.MinValue)
            {
                elem.SetAttribute("createTime", todo.CreateTime.ToString("yyyyMMddHHmm"));
            }
            if(todo.Checked == 1 && todo.CheckTime != DateTime.MinValue)
            {
                elem.SetAttribute("checkTime", todo.CheckTime.ToString("yyyyMMddHHmm"));
            }
            if (todo.Priority != 0)
            {
                elem.SetAttribute("priority", todo.Priority.ToString(CultureInfo.InvariantCulture));
            }

            //
            if (todo.Reminders != null && todo.Reminders.Count > 0)
            {
                var remindersElem = CreateRemindersElement(doc, todo.Reminders);
                elem.AppendChild(remindersElem);
            }

            //
            if (todo.Tags != null && todo.Tags.Count > 0)
            {
                var tagsElem = CreateTagsElement(doc, todo.Tags);
                elem.AppendChild(tagsElem);
            }

            return elem;
        }

        private static XmlElement CreateTagsElement(XmlDocument doc, IList<string> tags)
        {
            var elem = doc.CreateElement("tags");
            var sortedTags = new List<string>(tags);
            sortedTags.Sort();
            elem.InnerText = string.Join(" ", sortedTags.ToArray());
            return elem;
        }

        private static XmlElement CreateRemindersElement(XmlDocument doc, List<Reminder> reminders)
        {
            var elem = doc.CreateElement("reminders");

            foreach (var reminder in reminders)
            {
                var reminderElem = CreateReminderElement(doc, reminder);
                elem.AppendChild(reminderElem);
            }

            return elem;
        }

        private static XmlNode CreateReminderElement(XmlDocument doc, Reminder reminder)
        {
            var elem = doc.CreateElement("reminder");

            AddChildElement(doc, elem, "type", reminder.Type.ToString());
            if (reminder.Type == ReminderType.Email)
            {
                //AddChildElement(doc, elem, "to", (reminder as EmailReminder).To);
                AddChildElement(doc, elem, "to", App.Settings.EmailTo);
            }
            var timingElem = AddChildElement(doc, elem, "timing", reminder.Timing.Value);
            timingElem.SetAttribute("type", reminder.Timing.Type.ToString());

            return elem;
        }

        private static XmlElement AddChildElement(XmlDocument doc, XmlElement parentElem,
                                                  string name, string content)
        {
            var elem = doc.CreateElement(name);
            if (content != null && content.IndexOf('\n') != -1)
            {
                if (content.IndexOf('\r') == -1)
                {
                    content = content.Replace("\n", "\r\n");
                }
            }
            elem.InnerText = content;
            parentElem.AppendChild(elem);
            return elem;
        }
    }
}